import validate from "./validate.js";

// 缓存系统信息，避免重复调用
let systemInfoCache = null;
let systemInfoCacheTime = 0;
const CACHE_DURATION = 60000; // 1分钟缓存

/**
 * @description 获取系统信息（带缓存）
 * @returns {Object} 系统信息对象
 */
function getSystemInfo() {
  const now = Date.now();
  if (!systemInfoCache || now - systemInfoCacheTime > CACHE_DURATION) {
    try {
      systemInfoCache = uni.getSystemInfoSync();
      systemInfoCacheTime = now;
    } catch (error) {
      console.warn("[SC-UI] 获取系统信息失败:", error);
      // 返回默认值
      systemInfoCache = {
        windowWidth: 750,
        windowHeight: 1334,
        pixelRatio: 2,
      };
    }
  }
  return systemInfoCache;
}

/**
 * @description 转换px为rpx
 * @param {number|string} px 要转换的px值
 * @returns {number} 转换后的rpx值
 */
function px2rpx(px) {
  const sysInfo = getSystemInfo();

  // 处理字符串类型输入
  if (typeof px === "string") {
    const str = px.trim();
    // 处理带rpx单位的字符串
    if (/(rpx|upx)$/.test(str)) {
      return parseFloat(str);
    }
    // 处理纯数字字符串
    if (validate.isNumber(str)) {
      const num = parseFloat(str);
      return parseInt((num / sysInfo.windowWidth) * 750);
    }

    // 处理带px单位的字符串
    if (str.endsWith("px")) {
      const num = parseFloat(str);
      return parseInt((num / sysInfo.windowWidth) * 750);
    }
  }

  // 处理数字类型输入
  if (typeof px === "number" && !isNaN(px)) {
    return parseInt((px / sysInfo.windowWidth) * 750);
  }

  console.warn("[SC-UI] px2rpx: 参数格式无效", px);
  return 0;
}

/**
 * @description 转换rpx为px
 * @param {number|string} rpx 要转换的rpx值
 * @returns {number} 转换后的px值
 */
function rpx2px(rpx) {
  const sysInfo = getSystemInfo();

  // 处理字符串类型输入
  if (typeof rpx === "string") {
    const str = rpx.trim();
    // 处理带rpx单位的字符串
    if (/(rpx|upx)$/.test(str)) {
      const num = parseFloat(str);
      return parseInt((num * sysInfo.windowWidth) / 750);
    }

    // 处理纯数字字符串
    if (validate.isNumber(str)) {
      const num = parseFloat(str);
      return parseInt((num * sysInfo.windowWidth) / 750);
    }

    // 处理带px单位的字符串
    if (str.endsWith("px")) {
      return parseFloat(str);
    }
  }

  // 处理数字类型输入
  if (typeof rpx === "number" && !isNaN(rpx)) {
    return parseInt((rpx * sysInfo.windowWidth) / 750);
  }

  console.warn("[SC-UI] rpx2px: 参数格式无效", rpx);
  return 0;
}

/**
 * @description 获取元素的矩形信息
 * @param {string} selector 选择器字符串
 * @param {boolean} all 是否获取所有匹配元素的信息，默认false
 * @returns {Promise} 包含元素矩形信息的Promise对象
 */
function getRect(selector, all) {
  return new Promise((resolve) => {
    uni
      .createSelectorQuery()
      .in(this)
      [all ? "selectAll" : "select"](selector)
      .boundingClientRect((rect) => {
        if (all && Array.isArray(rect) && rect.length) {
          resolve(rect);
        }
        if (!all && rect) {
          resolve(rect);
        }
      })
      .exec();
  });
}

/**
 * @description 补0
 * @param {number} num 要补0的数字
 * @param {number} length 目标长度
 * @returns {string} 补0后的字符串
 */
function padZero(num, length = 2) {
  return num.toString().padStart(length, "0");
}

/**
 * @description 生成唯一标识符
 * @param {Number} len uuid的长度
 * @returns {string} 生成的唯一标识符
 */
function guid(len = 32) {
  const chars =
    "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz".split("");
  const uuid = [];

  if (len) {
    for (let i = 0; i < len; i++)
      uuid[i] = chars[0 | (Math.random() * chars.length)];
  } else {
    let r;
    uuid[8] = uuid[13] = uuid[18] = uuid[23] = "-";
    uuid[14] = "4";

    for (let i = 0; i < 36; i++) {
      if (!uuid[i]) {
        r = 0 | (Math.random() * 16);
        uuid[i] = chars[i == 19 ? (r & 0x3) | 0x8 : r];
      }
    }
  }

  return uuid.join("");
}

/**
 * @description 添加单位，如果是字符串直接返回，否则加上rpx单位结尾
 * @param {string|number} value 需要添加单位的值
 * @param {string} unit 添加的单位名 默认:rpx
 * @returns {string|undefined} 带单位的值或undefined
 */
function addUnit(value, unit = "rpx") {
  if (value === undefined || value === null || value === "") {
    return undefined;
  }

  // 如果已经是带单位的值，直接返回
  if (
    typeof value === "string" &&
    /^-?\d+(\.\d+)?(rpx|px|em|rem|vw|vh|%)$/.test(value)
  ) {
    return value;
  }

  // 如果是数字，添加单位
  if (/^-?\d+(\.\d+)?$/.test(value)) {
    return `${value}${unit}`;
  }

  return value;
}

/**
 * @description 去除空格
 * @param {String} str 需要去除空格的字符串
 * @param {String} pos both(左右)|left|right|all 默认both
 * @returns {String} 处理后的字符串
 */
function trim(str, pos = "both") {
  str = String(str);

  if (pos == "both") {
    return str.replace(/^\s+|\s+$/g, "");
  }
  if (pos == "left") {
    return str.replace(/^\s*/, "");
  }
  if (pos == "right") {
    return str.replace(/(\s*$)/g, "");
  }
  if (pos == "all") {
    return str.replace(/\s+/g, "");
  }

  return str;
}

/**
 * @description 显示toast提示
 * @param {string} title 提示内容
 * @param {Object} params 可选参数，包含icon、duration等
 */
function toast(title, params = {}) {
  const { icon = "none", duration = 1500 } = params;
  uni.showToast({
    title,
    icon,
    duration,
  });
}

/**
 * @description 获取颜色值
 * @param {*} val 颜色值
 * @returns {string} 颜色值
 */
function getColor(val) {
  if (!val) return "";

  try {
    const colors = (uni.$sc && uni.$sc.config && uni.$sc.config.color) || {};
    if (colors && colors[val]) return colors[val];

    // 验证颜色值格式
    if (typeof val === "string") {
      // 支持的颜色格式：hex, rgb, rgba, hsl, hsla, 颜色关键字
      const colorRegex =
        /^(#([0-9A-F]{3}){1,2}|rgb\(\s*\d+\s*,\s*\d+\s*,\s*\d+\s*\)|rgba\(\s*\d+\s*,\s*\d+\s*,\s*\d+\s*,\s*[\d.]+\s*\)|hsl\(\s*\d+\s*,\s*\d+%\s*,\s*\d+%\s*\)|hsla\(\s*\d+\s*,\s*\d+%\s*,\s*\d+%\s*,\s*[\d.]+\s*\))$/i;

      if (colorRegex.test(val) || CSS.supports("color", val)) {
        return val;
      }
    }

    return val;
  } catch (error) {
    console.warn("[SC-UI] getColor: 颜色值处理失败", val, error);
    return val;
  }
}

/**
 * @description 将数字转换为两位十六进制字符串
 * @param {number} value - 输入的数字（0-255）
 * @returns {string} - 两位十六进制字符串
 */
function toHex(value) {
  const hex = value.toString(16);
  return hex.length === 1 ? "0" + hex : hex;
}

/**
 * @description 颜色转换工具函数
 * @param {string} color - 输入的颜色值（hex、rgb、rgba）
 * @param {string} targetFormat - 目标格式（hex、rgb、rgba）
 * @param {number} [alpha=1] - 可选的透明度（0-1），仅当目标格式为 rgba 时有效
 * @returns {string} - 转换后的颜色值
 */
function convertColor(color, targetFormat, alpha = 1) {
  // 检查输入颜色格式
  const hexRegex = /^#([A-Fa-f0-9]{6}|[A-Fa-f0-9]{3})$/;
  const rgbRegex =
    /^rgb\(\s*(\d{1,3}%?)\s*,\s*(\d{1,3}%?)\s*,\s*(\d{1,3}%?)\s*\)$/;
  const rgbaRegex =
    /^rgba\(\s*(\d{1,3}%?)\s*,\s*(\d{1,3}%?)\s*,\s*(\d{1,3}%?)\s*,\s*([01]?\.\d+|[01])\s*\)$/;

  // 解析输入颜色
  let r,
    g,
    b,
    a = 1;

  if (hexRegex.test(color)) {
    // 处理 hex 颜色
    let hex = color.replace("#", "");
    if (hex.length === 3) {
      hex = hex
        .split("")
        .map((c) => c + c)
        .join("");
    }
    r = parseInt(hex.substring(0, 2), 16);
    g = parseInt(hex.substring(2, 4), 16);
    b = parseInt(hex.substring(4, 6), 16);
  } else if (rgbRegex.test(color)) {
    // 处理 rgb 颜色
    const parts = color.match(rgbRegex);
    r = parseInt(parts[1]);
    g = parseInt(parts[2]);
    b = parseInt(parts[3]);
  } else if (rgbaRegex.test(color)) {
    // 处理 rgba 颜色
    const parts = color.match(rgbaRegex);
    r = parseInt(parts[1]);
    g = parseInt(parts[2]);
    b = parseInt(parts[3]);
    a = parseFloat(parts[4]);
  } else {
    throw new Error("颜色格式无效");
  }

  // 根据目标格式转换
  switch (targetFormat.toLowerCase()) {
    case "hex":
      return `#${toHex(r)}${toHex(g)}${toHex(b)}`;
    case "rgb":
      return `rgb(${r}, ${g}, ${b})`;
    case "rgba":
      return `rgba(${r}, ${g}, ${b}, ${alpha})`;
    default:
      throw new Error("目标格式无效");
  }
}

/**
 * @description 样式转换
 * 对象转字符串，或者字符串转对象
 * @param {object | string} customStyle 需要转换的目标
 * @param {String} target 转换的目的，object-转为对象，string-转为字符串
 * @returns {object|string}
 */
function addStyle(customStyle, target = "object") {
  // 字符串转字符串，对象转对象情形，直接返回
  if (
    validate.isEmpty(customStyle) ||
    (typeof customStyle === "object" && target === "object") ||
    (target === "string" && typeof customStyle === "string")
  ) {
    return customStyle;
  }

  // 字符串转对象
  if (target === "object") {
    // 去除字符串样式中的两端空格(中间的空格不能去掉，比如padding: 20px 0如果去掉了就错了)，空格是无用的
    customStyle = trim(customStyle);
    // 根据";"将字符串转为数组形式
    const styleArray = customStyle.split(";");
    const style = {};
    // 历遍数组，拼接成对象
    for (let i = 0; i < styleArray.length; i++) {
      // 'font-size:20px;color:red;'，如此最后字符串有";"的话，会导致styleArray最后一个元素为空字符串，这里需要过滤
      if (styleArray[i]) {
        const item = styleArray[i].split(":");
        style[trim(item[0])] = trim(item[1]);
      }
    }
    return style;
  }

  // 这里为对象转字符串形式
  let string = "";
  for (const i in customStyle) {
    // 驼峰转为中划线的形式，否则css内联样式，无法识别驼峰样式属性名
    const key = i.replace(/([A-Z])/g, "-$1").toLowerCase();
    string += `${key}:${customStyle[i]};`;
  }
  // 去除两端空格
  return trim(string);
}

/**
 * @description 深度合并多个对象。如果对象中有嵌套对象，会递归地进行合并。
 * @param {...Object} objects 多个对象参数，将被依次合并到一个新的对象中。
 * @returns {Object} 返回一个新的对象，该对象是将参数中的多个对象深度合并而成的。
 */
function deepMerge(...objects) {
  // 定义哪些值被视为无效值
  const isInvalid = (value) => {
    return value === null || value === undefined || value === "";
  };

  // 定义是否为普通对象（不是数组、日期等特殊对象）
  const isPlainObject = (value) => {
    return (
      value &&
      typeof value === "object" &&
      !Array.isArray(value) &&
      !(value instanceof Date) &&
      !(value instanceof RegExp)
    );
  };

  const merged = {};

  // 递归合并函数
  const mergeRecursive = (target, source) => {
    // 遍历源对象的属性
    for (const key in source) {
      if (source.hasOwnProperty(key)) {
        const sourceValue = source[key];
        const targetValue = target[key];

        // 如果源值无效，跳过
        if (isInvalid(sourceValue)) {
          continue;
        }

        // 如果源值和目标值都是普通对象，进行递归合并
        if (isPlainObject(sourceValue) && isPlainObject(targetValue)) {
          target[key] = mergeRecursive({ ...targetValue }, sourceValue);
        } else {
          // 否则直接赋值
          target[key] = sourceValue;
        }
      }
    }
    return target;
  };

  // 遍历所有输入对象
  objects.forEach((obj, index) => {
    // 确保处理的是对象类型
    if (obj && typeof obj === "object" && !Array.isArray(obj)) {
      mergeRecursive(merged, obj);
    } else if (obj !== null && obj !== undefined) {
      console.warn(`[SC-UI] deepMerge: 第${index + 1}个参数不是有效对象`, obj);
    }
  });

  return merged;
}

/**
 * @description 深度克隆
 * @param {object} obj 需要深度克隆的对象
 * @param {WeakMap} cache 缓存
 * @returns {*} 克隆后的对象或者原值（不是对象）
 */
function deepClone(obj, cache = new WeakMap()) {
  if (obj === null || typeof obj !== "object") return obj;
  if (cache.has(obj)) return cache.get(obj);

  let clone;
  try {
    if (obj instanceof Date) {
      clone = new Date(obj.getTime());
    } else if (obj instanceof RegExp) {
      clone = new RegExp(obj);
    } else if (obj instanceof Map) {
      clone = new Map();
      obj.forEach((value, key) => {
        clone.set(deepClone(key, cache), deepClone(value, cache));
      });
    } else if (obj instanceof Set) {
      clone = new Set();
      obj.forEach((value) => {
        clone.add(deepClone(value, cache));
      });
    } else if (Array.isArray(obj)) {
      clone = obj.map((item) => deepClone(item, cache));
    } else {
      clone = Object.create(Object.getPrototypeOf(obj));
      for (const key in obj) {
        if (obj.hasOwnProperty(key)) {
          clone[key] = deepClone(obj[key], cache);
        }
      }
    }

    cache.set(obj, clone);
    return clone;
  } catch (error) {
    console.warn("[SC-UI] deepClone: 克隆失败", error);
    return obj;
  }
}

export default {
  // 系统相关
  getSystemInfo,
  px2rpx,
  rpx2px,
  getRect,

  // 字符串处理
  padZero,
  guid,
  addUnit,
  trim,

  // UI交互
  toast,

  // 样式处理
  getColor,
  toHex,
  convertColor,
  addStyle,

  // 对象处理
  deepMerge,
  deepClone,
};
